/**
 *向线程函数传递参数 
 普通参数
 引用参数
 类成员作为线程对象
 线程参数的移动
 */
#include <thread>
#include <iostream>

void some_function()
{
}

void some_other_function(int)
{
}

std::thread f()
{
    void some_function();
    return std::thread(some_function);
}
std::thread g()
{
    void some_other_function(int);
    std::thread t(some_other_function, 42);
    return t;
}

void f1(int i, std::string const &s)
{

    std::cout << "i " << i << std::endl;
    std::cout << "buffer " << s << std::endl;
    std::cout << "thread id " << std::this_thread::get_id() << std::endl;
}
void oops(int some_param)
{
    char buffer[1024];
    sprintf(buffer, "%i", some_param);
    std::thread t(f1, 3, "hello");               // hello char const * 类型会在线程上下文中转化为 std::string 类型，
    std::thread _t1(f1, 4, buffer);              //buffer 是一个指针变量，有可能会在buffer 转化为 std::string 前出问题
    std::thread _t2(f1, 5, std::string(buffer)); //需要先转化成 std::string ;避免空指针
    t.join();
    _t1.join();
    _t2.join();
}
//引用传递到线程，但是线程无视用户期望的类型，直接进行拷贝，
void update_data_for_widget(int id, std::string &str) //要求返回修改的, not const
{
    std::cout << "id " << id << std::endl;
    str = "abc is modify";
    std::cout << "str " << str << std::endl;
}
void oops_again(int id)
{
    std::string str = "1234";
    std::thread t(update_data_for_widget, 6, std::ref(str)); // 传递引用需要使用 std::ref,否则 线程方法参数需要是常量引用 const&
    t.join();
    std::cout << "str " << str << std::endl;
}

class x
{
public:
    void do_lenghty_work(int num) { num = 7; };
};
void oops_2()
{
    x my_x;
    int num(5);
    std::thread t(&x::do_lenghty_work, &my_x, num); // 类成员函数可以作为线程函数，第二个参数需要是类对象，第三个参数是类成员函数参数
    //提供的参数可以移动但是不能拷贝 ？？ 没有验证出来
    t.join();
    std::cout << "x::num " << num << std::endl;
}

void process_big_object(std::unique_ptr<std::string> str)
{
    std::cout << "str " << *str << std::endl;
}
void oops_big_object()
{
    std::unique_ptr<std::string> p(new std::string("12345"));
    std::thread t(process_big_object,std::move(p));  // std::move 保证只有一个线程实例拥有对象所有权
    t.join();
    //std::cout << "str p " << *p << std::endl; //所有权转移不能在使用
}

int main()
{
    std::thread t1 = f();
    t1.join();
    std::thread t2 = g();
    t2.join();

    oops(123456);
    oops_again(1);
    oops_2();
    oops_big_object();
}